import { ref, reactive, computed, watch, type Ref } from 'vue'
import { isValidEmail, isValidPhone, isValidIdCard, isEmpty } from '~/utils/common'

// 验证规则类型
export type ValidationRule = {
  required?: boolean
  min?: number
  max?: number
  minLength?: number
  maxLength?: number
  pattern?: RegExp
  email?: boolean
  phone?: boolean
  idCard?: boolean
  number?: boolean
  integer?: boolean
  positive?: boolean
  url?: boolean
  custom?: (value: any) => boolean | string
  message?: string
}

// 字段验证结果
export interface FieldValidation {
  isValid: boolean
  message: string
  isDirty: boolean
  isTouched: boolean
}

// 表单验证配置
export interface ValidationConfig {
  validateOnInput?: boolean
  validateOnBlur?: boolean
  validateOnSubmit?: boolean
  showErrorsOnTouch?: boolean
  debounceMs?: number
}

// 验证器函数类型
export type Validator = (value: any, rule: ValidationRule) => boolean | string

// 内置验证器
const validators: Record<string, Validator> = {
  required: (value, rule) => {
    if (!rule.required) return true
    if (isEmpty(value)) return rule.message || '此字段为必填项'
    return true
  },
  
  min: (value, rule) => {
    if (rule.min === undefined) return true
    if (typeof value === 'number' && value < rule.min) {
      return rule.message || `值不能小于 ${rule.min}`
    }
    return true
  },
  
  max: (value, rule) => {
    if (rule.max === undefined) return true
    if (typeof value === 'number' && value > rule.max) {
      return rule.message || `值不能大于 ${rule.max}`
    }
    return true
  },
  
  minLength: (value, rule) => {
    if (rule.minLength === undefined) return true
    const length = String(value || '').length
    if (length < rule.minLength) {
      return rule.message || `长度不能少于 ${rule.minLength} 个字符`
    }
    return true
  },
  
  maxLength: (value, rule) => {
    if (rule.maxLength === undefined) return true
    const length = String(value || '').length
    if (length > rule.maxLength) {
      return rule.message || `长度不能超过 ${rule.maxLength} 个字符`
    }
    return true
  },
  
  pattern: (value, rule) => {
    if (!rule.pattern) return true
    if (!rule.pattern.test(String(value || ''))) {
      return rule.message || '格式不正确'
    }
    return true
  },
  
  email: (value, rule) => {
    if (!rule.email) return true
    if (!isEmpty(value) && !isValidEmail(String(value))) {
      return rule.message || '请输入有效的邮箱地址'
    }
    return true
  },
  
  phone: (value, rule) => {
    if (!rule.phone) return true
    if (!isEmpty(value) && !isValidPhone(String(value))) {
      return rule.message || '请输入有效的手机号码'
    }
    return true
  },
  
  idCard: (value, rule) => {
    if (!rule.idCard) return true
    if (!isEmpty(value) && !isValidIdCard(String(value))) {
      return rule.message || '请输入有效的身份证号码'
    }
    return true
  },
  
  number: (value, rule) => {
    if (!rule.number) return true
    if (!isEmpty(value) && isNaN(Number(value))) {
      return rule.message || '请输入有效的数字'
    }
    return true
  },
  
  integer: (value, rule) => {
    if (!rule.integer) return true
    if (!isEmpty(value) && !Number.isInteger(Number(value))) {
      return rule.message || '请输入整数'
    }
    return true
  },
  
  positive: (value, rule) => {
    if (!rule.positive) return true
    if (!isEmpty(value) && Number(value) <= 0) {
      return rule.message || '请输入正数'
    }
    return true
  },
  
  url: (value, rule) => {
    if (!rule.url) return true
    if (!isEmpty(value)) {
      try {
        new URL(String(value))
      } catch {
        return rule.message || '请输入有效的URL地址'
      }
    }
    return true
  },
  
  custom: (value, rule) => {
    if (!rule.custom) return true
    return rule.custom(value)
  }
}

// 防抖函数
const debounce = <T extends (...args: any[]) => any>(
  func: T,
  wait: number
): T => {
  let timeout: NodeJS.Timeout | null = null
  
  return ((...args: Parameters<T>) => {
    if (timeout) clearTimeout(timeout)
    timeout = setTimeout(() => func(...args), wait)
  }) as T
}

// 单字段验证 Composable
export const useFieldValidation = (
  initialValue: any = '',
  rules: ValidationRule[] = [],
  config: ValidationConfig = {}
) => {
  const {
    validateOnInput = true,
    validateOnBlur = true,
    debounceMs = 300
  } = config
  
  // 字段值
  const value = ref(initialValue)
  
  // 验证状态
  const validation = reactive<FieldValidation>({
    isValid: true,
    message: '',
    isDirty: false,
    isTouched: false
  })
  
  // 验证单个字段
  const validateField = (val: any): boolean => {
    validation.message = ''
    validation.isValid = true
    
    for (const rule of rules) {
      for (const [validatorName, validator] of Object.entries(validators)) {
        if (rule[validatorName as keyof ValidationRule] !== undefined) {
          const result = validator(val, rule)
          if (result !== true) {
            validation.isValid = false
            validation.message = typeof result === 'string' ? result : '验证失败'
            return false
          }
        }
      }
    }
    
    return true
  }
  
  // 防抖验证
  const debouncedValidate = debounceMs > 0 
    ? debounce(validateField, debounceMs)
    : validateField
  
  // 监听值变化
  watch(value, (newValue, oldValue) => {
    if (newValue !== oldValue) {
      validation.isDirty = true
    }
    
    if (validateOnInput && validation.isDirty) {
      debouncedValidate(newValue)
    }
  })
  
  // 手动验证
  const validate = (): boolean => {
    return validateField(value.value)
  }
  
  // 标记为已触摸
  const touch = (): void => {
    validation.isTouched = true
    if (validateOnBlur) {
      validate()
    }
  }
  
  // 重置验证状态
  const reset = (): void => {
    value.value = initialValue
    validation.isValid = true
    validation.message = ''
    validation.isDirty = false
    validation.isTouched = false
  }
  
  // 清除错误
  const clearError = (): void => {
    validation.isValid = true
    validation.message = ''
  }
  
  // 设置错误
  const setError = (message: string): void => {
    validation.isValid = false
    validation.message = message
  }
  
  return {
    value,
    validation: computed(() => validation),
    validate,
    touch,
    reset,
    clearError,
    setError,
    
    // 便捷属性
    isValid: computed(() => validation.isValid),
    isInvalid: computed(() => !validation.isValid),
    message: computed(() => validation.message),
    isDirty: computed(() => validation.isDirty),
    isTouched: computed(() => validation.isTouched),
    showError: computed(() => validation.isTouched && !validation.isValid)
  }
}

// 表单验证 Composable
export const useFormValidation = <T extends Record<string, any>>(
  initialValues: T,
  rules: Record<keyof T, ValidationRule[]>,
  config: ValidationConfig = {}
) => {
  const {
    validateOnSubmit = true,
    showErrorsOnTouch = true
  } = config
  
  // 表单数据
  const form = reactive<T>({ ...initialValues })
  
  // 字段验证器
  const fields = reactive<Record<keyof T, ReturnType<typeof useFieldValidation>>>({} as any)
  
  // 初始化字段验证器
  Object.keys(initialValues).forEach(key => {
    const fieldKey = key as keyof T
    (fields as any)[fieldKey] = useFieldValidation(
      initialValues[fieldKey],
      rules[fieldKey] || [],
      config
    )
    
    // 同步表单数据和字段值
    watch(
      () => (fields as any)[fieldKey].value,
      (newValue) => {
        (form as any)[fieldKey] = newValue
      }
    )
    
    watch(
      () => (form as any)[fieldKey],
      (newValue) => {
        if ((fields as any)[fieldKey].value !== newValue) {
          (fields as any)[fieldKey].value = newValue
        }
      }
    )
  })
  
  // 表单验证状态
  const isValid = computed(() => {
    return Object.values(fields).every(field => field.isValid)
  })
  
  const isInvalid = computed(() => !isValid.value)
  
  const isDirty = computed(() => {
    return Object.values(fields).some(field => field.isDirty)
  })
  
  const isTouched = computed(() => {
    return Object.values(fields).some(field => field.isTouched)
  })
  
  const errors = computed(() => {
    const result: Record<string, string> = {}
    Object.keys(fields).forEach(key => {
      const field = (fields as any)[key as keyof T]
      if (!field.isValid && (field.isTouched || !showErrorsOnTouch)) {
        result[key] = field.message
      }
    })
    return result
  })
  
  const hasErrors = computed(() => Object.keys(errors.value).length > 0)
  
  // 验证整个表单
  const validate = (): boolean => {
    let isFormValid = true
    
    Object.values(fields).forEach(field => {
      if (!field.validate()) {
        isFormValid = false
      }
      field.touch()
    })
    
    return isFormValid
  }
  
  // 验证指定字段
  const validateField = (fieldName: keyof T): boolean => {
    const field = (fields as any)[fieldName]
    if (field) {
      field.touch()
      return field.validate()
    }
    return true
  }
  
  // 重置表单
  const reset = (): void => {
    Object.keys(fields).forEach(key => {
      const fieldKey = key as keyof T
      (fields as any)[fieldKey].reset()
      (form as any)[fieldKey] = initialValues[fieldKey]
    })
  }
  
  // 重置验证状态（保留数据）
  const resetValidation = (): void => {
    Object.values(fields).forEach(field => {
      field.clearError()
    })
  }
  
  // 设置表单数据
  const setValues = (values: Partial<T>): void => {
    Object.keys(values).forEach(key => {
      const fieldKey = key as keyof T
      if (fieldKey in form) {
        (form as any)[fieldKey] = values[fieldKey]!
      }
    })
  }
  
  // 设置字段错误
  const setFieldError = (fieldName: keyof T, message: string): void => {
    const field = (fields as any)[fieldName]
    if (field) {
      field.setError(message)
    }
  }
  
  // 设置多个字段错误
  const setErrors = (fieldErrors: Record<keyof T, string>): void => {
    Object.keys(fieldErrors).forEach(key => {
      const fieldKey = key as keyof T
      setFieldError(fieldKey, fieldErrors[fieldKey])
    })
  }
  
  // 清除字段错误
  const clearFieldError = (fieldName: keyof T): void => {
    const field = (fields as any)[fieldName]
    if (field) {
      field.clearError()
    }
  }
  
  // 清除所有错误
  const clearErrors = (): void => {
    Object.values(fields).forEach(field => {
      field.clearError()
    })
  }
  
  // 提交处理
  const handleSubmit = (onSubmit: (values: T) => void | Promise<void>) => {
    return async (event?: Event) => {
      if (event) {
        event.preventDefault()
      }
      
      if (validateOnSubmit) {
        if (!validate()) {
          return
        }
      }
      
      try {
        await onSubmit({ ...(form as any) })
      } catch (error) {
        console.error('Form submission error:', error)
      }
    }
  }
  
  return {
    // 表单数据
    form,
    fields,
    
    // 验证状态
    isValid,
    isInvalid,
    isDirty,
    isTouched,
    errors,
    hasErrors,
    
    // 验证方法
    validate,
    validateField,
    
    // 重置方法
    reset,
    resetValidation,
    
    // 数据操作
    setValues,
    
    // 错误处理
    setFieldError,
    setErrors,
    clearFieldError,
    clearErrors,
    
    // 提交处理
    handleSubmit
  }
}

// 常用验证规则预设
export const validationRules = {
  required: (message?: string): ValidationRule => ({
    required: true,
    message: message || '此字段为必填项'
  }),
  
  email: (message?: string): ValidationRule => ({
    email: true,
    message: message || '请输入有效的邮箱地址'
  }),
  
  phone: (message?: string): ValidationRule => ({
    phone: true,
    message: message || '请输入有效的手机号码'
  }),
  
  idCard: (message?: string): ValidationRule => ({
    idCard: true,
    message: message || '请输入有效的身份证号码'
  }),
  
  minLength: (min: number, message?: string): ValidationRule => ({
    minLength: min,
    message: message || `长度不能少于 ${min} 个字符`
  }),
  
  maxLength: (max: number, message?: string): ValidationRule => ({
    maxLength: max,
    message: message || `长度不能超过 ${max} 个字符`
  }),
  
  length: (min: number, max: number, message?: string): ValidationRule[] => [
    {
      minLength: min,
      message: message || `长度必须在 ${min}-${max} 个字符之间`
    },
    {
      maxLength: max,
      message: message || `长度必须在 ${min}-${max} 个字符之间`
    }
  ],
  
  number: (message?: string): ValidationRule => ({
    number: true,
    message: message || '请输入有效的数字'
  }),
  
  integer: (message?: string): ValidationRule => ({
    integer: true,
    message: message || '请输入整数'
  }),
  
  positive: (message?: string): ValidationRule => ({
    positive: true,
    message: message || '请输入正数'
  }),
  
  range: (min: number, max: number, message?: string): ValidationRule[] => [
    {
      min,
      message: message || `值必须在 ${min}-${max} 之间`
    },
    {
      max,
      message: message || `值必须在 ${min}-${max} 之间`
    }
  ],
  
  pattern: (pattern: RegExp, message?: string): ValidationRule => ({
    pattern,
    message: message || '格式不正确'
  }),
  
  url: (message?: string): ValidationRule => ({
    url: true,
    message: message || '请输入有效的URL地址'
  }),
  
  custom: (validator: (value: any) => boolean | string, message?: string): ValidationRule => ({
    custom: validator,
    message
  }),
  
  // 密码强度验证
  password: (message?: string): ValidationRule => ({
    pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d@$!%*?&]{8,}$/,
    message: message || '密码必须包含大小写字母和数字，长度至少8位'
  }),
  
  // 确认密码验证
  confirmPassword: (passwordRef: Ref<string>, message?: string): ValidationRule => ({
    custom: (value: string) => {
      if (value !== passwordRef.value) {
        return message || '两次输入的密码不一致'
      }
      return true
    }
  })
}